﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using AirLinq.Expressions;
using System.Data;
using System.Reflection;
using AirLinq.Providers;
using AirLinq.Meta;
using System.Xml;
using System.IO;
using AirLinq.Dynamic;
namespace AirLinq {
	public class AirLinqDataContext {
		private readonly MetaModel _model;
		private readonly IDbConnection _connection;
		private readonly IDatabaseProvider _databaseProvider;

		private readonly CodeGenerator _codeGenerator = CodeGenerator.Instance;
 
		public AirLinqDataContext(Stream xmlModel, IDbConnection connection)
			: this(ModelFromStream(xmlModel), connection) {
		}
		public AirLinqDataContext(XmlReader xmlModel, IDbConnection connection)
			: this(ModelFromXml(xmlModel), connection){
		}
		private static MetaModel ModelFromStream(Stream stream){
			using (var reader= XmlReader.Create(stream)){
				return ModelFromXml(reader);
			}
		}
		private static MetaModel ModelFromXml(XmlReader xmlModel) {
			return XmlModelReader.ReadMapping(xmlModel);
		}
		public AirLinqDataContext(MetaModel model, IDbConnection connection) {
			_connection = connection;
			_model = model;
			_databaseProvider = DatabaseProviderFactory.CreateDatabaseProvider(connection);
		}
		public IQueryable<T> GetTable<T>() {
			var metaType=GetTableForType(typeof(T));
			//Expression<Func<T,T>> selector = row => row;
			Expression selectExpression = //Expression.Call(QueryableMethods.QSelect1.MakeGenericMethod(typeof(T), typeof(T)),
				Expression.Call(QueryableMethods.PFromTable.MakeGenericMethod(typeof(T)), Expression.Constant(metaType.TableName)); //,
//				Expression.Quote(selector));
			var provider = new AirLinqProvider(this, metaType);
			return provider.CreateQuery<T>(selectExpression);
		}
		private MetaType GetTableForType(Type type) {
			var metaTypes=_model.GetMetaType(type);
			if (metaTypes == null || metaTypes.Length != 1) {
				throw new AmbiguousMatchException("MetaType for type not found");
			}
			return metaTypes[0];
		}
		public IDatabaseProvider DatabaseProvider {
			get {
				return _databaseProvider;
			}
		}
		public IDbConnection Connection {
			get {
				return _connection;
			}
		}
		internal static IQueryable<T> From<T>(string tableName) {
			throw new NotSupportedException();
		}
		public CodeGenerator CodeGenerator {
			get {
				return _codeGenerator;
			}
		}
	}
}
